Block的理解
####什么是Block
带有自动变量的匿名函数
- 自动变量
- 匿名函数
####Block的使用
- 作为变量
1 | //定义 |
- 作为属性
1 | @property (nonatomic,copy)returnType (^blockName)(Parameters); |
- 作为函数参数
1 | - (void)testMethodWithHandler:(returnType (^blockName)(Parameters))block; |
- 使用typedef
1 | typedef returntype (^BlockName)(Parameters); |
####Block的本质
1 | #define BLOCK_DESCRIPTOR_1 1 |
objc中对象的定义:首地址是isa的结构体指针,所以block是对象类型
block的class类型:
- _NSConcreteStackBlock 栈上创建的block
- _NSConcreteMallocBlock 堆上创建的block
- _NSConcreteGlobalBlock 作为全局变量的block
- _NSConcreteWeakBlockVariable
- _NSConcreteAutoBlock
- _NSConcreteFinalizingBlock
#####_NSConcreteGlobalBlock
创建block时,就是声明struct,初始化struct的成员;执行block,就是调用struct的函数指针,编译完成之后,block中的代码会被提取出来,成为单独的C函数,调用这个C函数,并把struct指针传递过去.block的实际作用就相当于C语言的匿名函数.
全局block:block内部没有捕获任何外部变量就是一个全局block类型,调用block(),和C语言的函数无异,不需要考虑其生命周期
#####_NSConcreteStackBlock
当block内部引用了外部变量,当struct被创建时,它是存在于函数的栈帧上的,其class是固定的_NSConcreteStackBlock类型.其捕获的变量是会赋值到结构体的成员上,所以当block初始化完成之后,捕获的变量不能更改.
当函数返回时,函数的栈帧被销毁,这个block的内存也会被清除.所以当函数结束后仍然需要这个block时,就必须用Block_copy()方法将它拷贝到堆上,核心动作即(申请内存,将栈数据复制过去,将class改成_NSConcreteMallocBlock,向捕获的对象发送retain,增加block的引用计数)
block就是个匿名函数,只不过我们给了一个变量来引用这个匿名函数,在需要的时候调用。但是,栈block会随着函数栈帧的销毁而销毁,这样一来,我们用之前做引用的变量再去调用这么一块被销毁的内存,就会出现内存崩溃。